#include "../../include/drawer/raster.hpp"

#include<iostream>
using namespace std;

namespace drawer{

    // 判断一个点是否在二维的三角形的内部
bool isInsiderTriangle(Dot p,Dot a,Dot b,Dot c){
    // 得到所有向量
    Vector2 ab((b-a).x,(b-a).y);
    Vector2 bc((c-b).x,(c-b).y);
    Vector2 ca((a-c).x,(a-c).y);
    Vector2 ap((p-a).x,(p-a).y);
    Vector2 bp((p-b).x,(p-b).y);
    Vector2 cp((p-c).x,(p-c).y);
    // 得到所有叉乘
    float ab_ap=ab^ap;
    float bc_bp=bc^bp;
    float ca_cp=ca^cp;
    // 判断是否在三角形的内部
    return (ab_ap >= 0 && bc_bp >= 0 && ca_cp >= 0) || (ab_ap <= 0 && bc_bp <= 0 && ca_cp <= 0);
}
float getZDepthValue(Dot p,Dot a,Dot b,Dot c){
    // 利用重心坐标法
    // 得到所有向量
    Vector2 ab((b.x-a.x),(b.y-a.y));
    Vector2 bc((c.x-b.x),(c.y-b.y));
    Vector2 ca((a.x-c.x),(a.y-c.y));
    Vector2 ap((p.x-a.x),(p.y-a.y));
    Vector2 bp((p.x-b.x),(p.y-b.y));
    Vector2 cp((p.x-c.x),(p.y-c.y));
    // bc，bp的叉乘为小三角形的面积，ab叉乘ac为大三角形面积
    float alpha=((bc^bp)/(ab^ca));
    float beta=((ca^cp)/(ab^ca));
    float gamma=1-alpha-beta;
    // 得到z的值
    float z=alpha*a.z+beta*b.z+gamma*c.z;
    return z;
}


    void Raster::rasterizeDot(Screen& screen,object::World world){
        // 首先从相机得到应该使用到的MVP矩阵
        auto mvp=world.camera.MVP();
        // 视口变化矩阵
        auto viewPort=transformation::ViewPort::viewPortMatrix(screen.width,screen.height);
        // 循环利用矩阵对每一个物体的顶点都进行一次变换
        for (auto& object: world.objects){
            for(auto& vertex: object.vertices){
                auto vertexMVP=mvp*vertex;
                vertex=viewPort*vertexMVP;
                // 现在已经转化为了屏幕坐标了
                if(vertex.x>=0 && vertex.x<=screen.width && vertex.y>=0 && vertex.y<=screen.height){
                    //一个点太小了，画大一点
                    screen.updateScreenPixel(vertex.x,vertex.y,1,0,0);
                    screen.updateScreenPixel(vertex.x+1,vertex.y,1,0,0);
                    screen.updateScreenPixel(vertex.x,vertex.y+1,1,0,0);
                    screen.updateScreenPixel(vertex.x,vertex.y-1,1,0,0);
                    screen.updateScreenPixel(vertex.x-1,vertex.y,1,0,0);
                }
            }
        }
    }
    void Raster::rasterizeColorTriangle(Screen& screen,object::ColorWorld world){
        // 首先从相机得到应该使用到的MVP矩阵
    auto mvp = world.camera.MVP();
    auto viewPort = transformation::ViewPort::viewPortMatrix(screen.width, screen.height);

    //得到最终的矩阵
    auto vmvp =viewPort*mvp;
    for (auto& vertex : world.vertices) {
        vertex = vmvp * vertex;
        //打印每个顶点
        screen.updateScreenPixel(vertex.x,vertex.y,1,0,0);
    }
    //在屏幕范围内寻找每个三角形的bounding box
    for (auto& triangle : world.colorTriangles) {
        Dot a = world.vertices[triangle.index1];
        Dot b = world.vertices[triangle.index2];
        Dot c = world.vertices[triangle.index3];

        // 计算bounding box
        int minX = std::min({a.x, b.x, c.x});
        int maxX = std::max({a.x, b.x, c.x});
        int minY = std::min({a.y, b.y, c.y});
        int maxY = std::max({a.y, b.y, c.y});

        //只循环bounding box范围内的像素
        for (int i = minX; i <= maxX; ++i) {
            for (int j = minY; j <= maxY; ++j) {
                if (isInsiderTriangle(Dot(i, j), a, b, c)) {
                    screen.updateScreenPixel(i, j, triangle.red, triangle.green, triangle.blue);
                }
            }
        }
    }
}

    void Raster::rasterizeColorTriangleWithZBuffer(Screen& screen,object::ColorWorld world){
        auto mvp = world.camera.MVP();
        auto viewPort = transformation::ViewPort::viewPortMatrix(screen.width, screen.height);

        auto vmvp=viewPort*mvp;

        for (auto& vertex : world.vertices) {
            vertex = vmvp * vertex;
            //打印每个顶点为红色，这里可以以后删除掉
            screen.updateScreenPixel(vertex.x,vertex.y,1,0,0);
        }

        // 新建一个二维数组，用来存储每个像素的深度
        float** depthBuffer = new float*[screen.width + 1];
        for(int i=0;i<=screen.width;i++){
            depthBuffer[i]=new float[screen.height + 1];
        }

        //在屏幕范围内寻找每个三角形的bounding box，从而缩小排查的范围
        for (auto& triangle : world.colorTriangles) {
            Dot a = world.vertices[triangle.index1];
            Dot b = world.vertices[triangle.index2];
            Dot c = world.vertices[triangle.index3];

            // 计算bounding box
            int minX = std::min({a.x, b.x, c.x});
            int maxX = std::max({a.x, b.x, c.x});
            int minY = std::min({a.y, b.y, c.y});
            int maxY = std::max({a.y, b.y, c.y});

            //只循环bounding box范围内的像素，计算每个像素是不是在三角形内部
            for (int i = minX; i <= maxX; ++i) {
                for (int j = minY; j <= maxY; ++j) {
                    if (isInsiderTriangle(Dot(i, j), a, b, c)) {
                        // 在三角形内部，进行深度计算并存储。
                        auto z=getZDepthValue(Dot(i, j), a, b, c);
                        // 如果当前像素的深度大于新的深度，则更新深度并更新颜色
                        if (depthBuffer[i][j] < z) {
                            depthBuffer[i][j] = z;
                            screen.updateScreenPixel(i, j, triangle.red, triangle.green, triangle.blue);
                        }else{
                            // 如果当前像素的深度小于新的深度，则不更新深度和颜色
                            continue;
                        }
                    }
                }
            }
        }
    }



}